#include "Bullet.h"
#include "Environment.h"
#include "PublicMarcos.h"
#include "ScriptEngine.h"
#include "GameRoom.h"
#include <algorithm>
#include <boost/mem_fn.hpp>

BulletInfo::BulletInfo( hgeSprite* sprite,float x, float y, float vx, float vy, float rot,float pa,int type ) : m_sprite(sprite),m_x(x),m_y(y),m_vx(vx),m_vy(vy),m_rotation(rot),m_type(type),m_clear(false),m_behavType(_TRACE_NOTARGET),sx(x),sy(y),stime(GameRoom::getLiveTime()),par(pa)
{
}

BulletInfo::~BulletInfo()
{
}

void BulletInfo::Update()
{
		m_x+=m_vx;
		m_y+=m_vy;
	if (m_x>_WINDOWS_WIDTH || m_x<0 || m_y<0 || m_y>_WINDOWS_HEIGHT)
		m_clear = true;
}

void BulletInfo::Update(float tx,float ty)
{
	m_x+=m_vx;
	m_y+=m_vy;
	if (m_behavType==_TRACE_TARGETING) {
		float dx = tx-m_x;
		float dy = ty-m_y;
		m_vx+=(dx-m_vx) * _BULLET_WEIGHT;
		m_vy+=(dy-m_vy) *_BULLET_WEIGHT;
		float speed = m_vx*m_vx+m_vy*m_vy;
		if (speed>_BULLET_CITY*_BULLET_CITY) {
			speed=sqrt(speed);
			m_vx = m_vx * _BULLET_CITY /speed;
			m_vy = m_vy * _BULLET_CITY /speed;
		}
	}
	if (m_x>_WINDOWS_WIDTH || m_x<0 || m_y<0 || m_y>_WINDOWS_HEIGHT)
		m_clear = true;
}

void BulletInfo::Update( const char* funcname )
{
	ScriptEngine::CallBulletFunc(funcname,this,GameRoom::getPlayerX(),GameRoom::getPlayerY(),GameRoom::getLiveTime());
	if (m_x>_WINDOWS_WIDTH || m_x<0 || m_y<0 || m_y>_WINDOWS_HEIGHT)
		m_clear = true;
}
void BulletInfo::Render()
{
	m_sprite->Render(m_x,m_y);
}

hgeRect* BulletInfo::getCollision(hgeRect *rect)
{
	return m_sprite->GetBoundingBoxEx(m_x,m_y,0,1,1,rect);
}


BulletManager::BulletManager()
{

}

void BulletManager::clearAll()
{
	std::for_each(m_ves.begin(),m_ves.end(),delete_object());
}

void BulletManager::addBullet( BulletInfo *bullet )
{
	m_ves.push_back(bullet);
}

void BulletManager::delBullet( BulletInfo *bullet )
{
	std::iter_swap(std::find(m_ves.begin(),m_ves.end(),bullet),m_ves.end()-1);
	m_ves.pop_back();
}

void BulletManager::delBullet( int num )
{
	std::iter_swap(m_ves.begin()+num,m_ves.end()-1);
	m_ves.pop_back();
}

void BulletManager::Update()
{
	for (unsigned int num = m_ves.size();num>0;num--)
	{
		UpdateCheck(m_ves[num-1]);
	}
}

void BulletManager::Render()
{
	std::for_each(m_ves.begin(),m_ves.end(),boost::mem_fn(&BulletInfo::Render));
}

BulletManager::~BulletManager()
{
	clearAll();
}

void BulletManager::UpdateCheck( BulletInfo *bullet )
{
	if (bullet->m_type==0)
		bullet->Update();
	else if (bullet->m_type==1)
		bullet->Update(m_targetX,m_targetY);
	else if (bullet->m_type < 2 + 26){
		static char bulletfunc[15] = "BulletTypeA";
		bulletfunc[strlen(bulletfunc)-1] = 'A' + bullet->m_type -2;
		bullet->Update(bulletfunc);
	}
	if (bullet->m_clear)
		delBullet(bullet);
}

void BulletManager::LockTarget( float dx, float dy )
{
	m_targetX = dx;m_targetY = dy;
	for (int i = 0; i < (int)m_ves.size(); i++){
		if (m_ves[i]->m_behavType != _TRACE_TARGETDEAD){
			m_ves[i]->m_behavType = _TRACE_TARGETING;
		}
	}
}

void BulletManager::unLockTarget()
{
	for (int i = 0; i < (int)m_ves.size(); i++){
		m_ves[i]->m_behavType = _TRACE_TARGETDEAD;
	}
}

int BulletManager::checkCollision( hgeRect *rect )
{
	int dmg = 0;
	for (unsigned int i = 0;i < m_ves.size();i++) {
		hgeRect tmp;
		if (rect->Intersect(m_ves[i]->getCollision(&tmp))) {
			m_ves[i]->m_clear = true;
			dmg+=_PLAYER_BASE_DMG;
		}
	}
	return dmg;
}

void BulletManager::clearBulllet()
{
	for_each(m_ves.begin(),m_ves.end(),delete_object());
	m_ves.clear();
}